TODO // 用宏或pragma保护头文件，防止重复包含

// 包含当前目录的文件
#include "row_view.hpp"

// 包含<cstdint>头文件，长度等成员函数用到。练习标准头文件的使用。
#include <cassert>
#include <cstddef>
#include <ostream>
#include <utility>

TODO // 定义命名空间sdu，测试程序针对该命名空间中的成员测试。

/**
 * @brief 矩阵`Matrix`类模板
 * 有1个模板参数：
 *    类型参数`T`，默认类型实参为`double`。
 */
template <TODO>
class TODO {
  // 类默认区域为私有部分：按顺序声明三个数据成员。

  /**
   * @brief 行数m_row，类型为size_t（无符号64位序数）。
  */
  TODO

  /**
   * @brief 列数m_col，类型为size_t。
  */
  TODO

  /**
   * @brief 矩阵数据指针m_arr，T类型指针。
  */
  TODO

  // 以下声明为公开部分：
TODO

  /**
   * @brief 默认构造函数。构造空矩阵（成员全0）
   * 目的：练习成员默认初始化的写法。m_row()或m_row{}都可以。
   */
  TODO

  /**
   * @brief 指定尺寸、初始数据的构造函数
   * @param row size_t
   * @param col size_t
   * @param pb  数据开始，T类型的常性指针。默认实参为nullptr。
   * @param pe  数据结束，T类型的常性指针。默认实参为nullptr。
   * @details 用[pb, pe)之间的数据逐行初始化矩阵。
   * 初始数据不足则剩余元素默认初始化。
   * 初始数据过多则忽略。
   * 目的：练习动态分配数组。
   */
  TODO

  /**
   * @brief 构造指定尺寸的方阵。初值全0。
   * @param n 行列数，size_t
   * @return 结果矩阵行数、列数都为n。元素全0。
   * @details 因为是单参数构造函数，需要声明为explicit，防止隐式转型。
   * 目的：练习构造函数的“委托”。练习explicit的使用。
   */
  TODO

  /**
   * @brief 定义名为identity的“静态”成员函数，构造指定尺寸的单位矩阵。
   * @param n size_t
   * @return 结果矩阵行数、列数都为n。对角线元素为1，其他元素全0。
   * 目的：练习静态成员函数。
   */
  TODO

  /**
   * @brief 析构函数
   *
   * @details 该矩阵类需要能在运行时指定行数、列数，动态分配数据。
   * 为避免资源泄露，析构函数必须释放所分配的内存。默认的析构函数不适用，需要实现。
   * 注意必须以数组形式删除m_arr。
   * 五大成员函数（BigFive）如果任一个的默认实现不满足要求，这五个都要自行实现。
   */
  TODO

  /**
   * @brief 交换函数swap
   * @param other 矩阵引用，需允许修改。
   * @details 交换this与other的内容。复杂度应为O(1)，与矩阵大小无关。
   * 不应用创建临时矩阵对象的方法交换。
   * 声明为不会发生异常（noexcept）
   * 交换函数不属于五大成员，但却是实现异常安全性的关键。
   * 不要返回this引用，支持级联操作虽然方便，但违背了“变动性操作不返回对象”的原则。
   */
  TODO

  /**
   * @brief 拷贝构造函数
   * @param other 矩阵的常性引用。常性：无意修改参数。引用：避免调用时复制实参。
   * @details 新矩阵的尺寸、数据内容与other完全相同。
   * T可能不是简单类型，所以不适用memcpy()复制数据。
   */
  TODO

  /**
   * @brief 拷贝赋值算符
   * @param other 矩阵的常性引用other。
   * @return 当前对象的引用。这是赋值算符的标准写法。
   * @details 赋值后矩阵的尺寸、数据元素应与other完全相同。
   * 处理“自赋值”的情况，比如：`m = m`，方法是比较this指针与other地址。
   * 内置类型比如int的赋值可以级联：`((i = 2) = 3)`
   * 所以赋值的返回值应当是“this引用”，保持一致的行为。
   */
  TODO

  /**
   * @brief 移动构造函数
   * @param other 矩阵“右值”引用，需允许修改。
   * @details other的数据转交给新矩阵。other设置为空矩阵。
   * Matrix可能是大对象，比如几百MB，即使复制都可能有很大开销，所以需要移动语义。
   * 移动后other需要置空，因此不能声明为常性。
   */
  TODO

  /**
   * @brief 移动赋值算符
   * @param other 矩阵“右值”引用，需允许修改。
   * @return 当前对象的引用。这是赋值算符的标准写法。
   * @details other的数据转交给this。other设置为空矩阵。
   * 处理“自赋值”的情况，比如：`m = m`。
   */
  TODO

  /**
   * @brief 矩阵判空is_empty
   * @return 当矩阵为空（行数或列数为0）返回true，其他情况返回false。
   * @details 注意不是判断元素全零。
   * 目的：练习查询性操作，通常声明为常性（const）、无异常（noexcept）。
   */
  TODO

  /**
   * @brief 行数
   * @return 矩阵的行数。size_t类型。
   * @details 声明为常性（const）、无异常（noexcept）。
   */
  TODO

  /**
   * @brief 列数
   * @return 矩阵的列数。size_t类型。
   * @details 声明为常性（const）、无异常（noexcept）。
   */
  TODO

  /**
   * @brief 修改矩阵尺寸resize
   * @param row 新的行数
   * @param col 新的列数
   * @details 利用构造函数和交换函数实现。
   * 先释放再分配的方式节省资源，但影响异常安全性，不推荐。
   */
  TODO

  /**
   * @brief 下标算符，获取矩阵行向量
   * @param row 行索引，size_t。
   * @return 返回RowView对象，指向矩阵第r行。
   * @details 若r不在[0, row)范围内，抛出invalid_argument异常。
   */
  TODO

  /**
   * @brief 下标算符，获取矩阵行向量
   * @param row 行索引，size_t。
   * @return 返回RowView对象，指向矩阵第r行。
   * @details 若r不在[0, row)范围内，抛出invalid_argument异常。
   */
  TODO

  /**
   * @brief 矩阵数乘自反赋值算符
   * @param t 乘数类型为T
   * @return this的引用。
   *
   * 请注意实现的顺序：数乘适合先实现自反赋值形式，再实现普通形式。
   */
  TODO

  /**
   * @brief 矩阵数乘算符
   * @param t 乘数类型为T
   * @return 新矩阵，数据为this与t之积。尺寸与this相同。
   * @details 应声明为常性成员函数。可用上面自反形式的数乘实现该函数。
   */
  TODO

  /**
   * @brief 矩阵乘法算符
   * @param 矩阵的常性引用other。this的列数应与other的行数相同。
   * @return 新矩阵，数据为this与other之积，行数与this相同，列数与other相同。
   * @details 若this的列数与other的行数不同，抛出invalid_argument异常。
   * 矩阵乘法很特别：
   *    不对称，不能轻易地交换两个运算对象。
   *    结果尺寸与this可能不同，计算需要反复引用两个对象的元素，不适合按自反赋值实现。
   */
  TODO

/****************************************************************************
 * 到此练习了基本的算符重载。
 * 矩阵的关系运算涉及浮点数的比较，感兴趣的同学可以试试，通常只需实现 == 和 < 算符。
 * 下标算符的重载写法可参考RowView类。
****************************************************************************/
TODO // 类结束

/**
 * @brief 重载输出算符
 * @param ost 输出流
 * @param mat 矩阵常性引用
 * @return 输出流实参的引用
 * @details 输出算符<<的首个参数必须是ostream，所以不能重载为Matrix类的成员。
 * 先输出左方括号，换行。
 * 逐行输出矩阵元素，默认格式。
 * 每行的元素之间用一个空格分隔，但行尾不要空格。
 * 最后输出右方括号，“不”换行。
 */
TODO: oprator<<

TODO // namespace 结束
